package org.geekbang.thinking.in.spring.bean.scope.web;

import org.geekbang.thinking.in.spring.bean.scope.BeanScopeDemo;
import org.geekbang.thinking.in.spring.bean.scope.ThreadLocalScope;
import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;

/**
 * 自定义 scope 示例
 *
 * @author: wangsiqi
 * @date: 2021/10/30
 */
public class ThreadLocalScopeDemo {

    @Bean
    @Scope(ThreadLocalScope.SCOPE_NAME)
    public User user() {
        return createUser();
    }

    private static User createUser() {
        User user = new User();
        user.setId(System.nanoTime());
        return user;
    }

    public static void main(String[] args) {
        // 1、创建 BeanFactory 容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // 2、注册 Configuration Class（配置类） -> Spring Bean
        context.register(ThreadLocalScopeDemo.class);

        context.addBeanFactoryPostProcessor(beanFactory -> {
            // 注册自定义 scope
            beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
        });

        // 3、启动 Spring 应用上下文
        context.refresh();

        scopedBeansByLookUp(context);

        ///5、关闭 Spring 应用上下文
        context.close();
    }

    private static void scopedBeansByLookUp(AnnotationConfigApplicationContext context) {
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    // user 是共享的 Bean 对象
                    User user = context.getBean("user", User.class);
                    System.out.printf("threadId: %d, user: %s", Thread.currentThread().getId(), user);
                }
            });
            thread.start();

            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
